package net.oov.identify.model;

import java.util.HashMap;
import java.util.Map;

public class CharTree implements StatusNode{

	private Boolean isLeaf;
	private Integer freq;//0 is not a word , >0 is word
	private Double conf;
	private Double mi;
	private Integer maxSubNodesLength;
	private Integer level;//the value of first level is 0
	private Boolean isWord = Boolean.FALSE;
	private Map<Character,CharTree> subTrees;
	
	public CharTree(CharSequence word,int offset){
		this.isLeaf = Boolean.FALSE;
		this.maxSubNodesLength = 0;
		this.subTrees = new HashMap<Character,CharTree>();
		this.level = offset;
		this.freq = 0;
	}
	
	public void addNodes(CharSequence word) {
		if(word.length()-1-level>maxSubNodesLength){
			maxSubNodesLength = word.length()-1-level;
		}
		int offset = level+1;//sub node
		CharTree subTree = this.subTree(word.charAt(offset));
		if(subTree == null){//no find the subTree of this word
			subTree = new CharTree(word,offset);//create new tree,freq is 1
			subTrees.put(word.charAt(offset), subTree);//put it into sub tree
			if(this.isLeaf)this.isLeaf = Boolean.FALSE;//current tree is not leaf
			if(word.length()-1==offset){//the length of word equals the sub tree's level
				subTree.isLeaf = Boolean.TRUE;//sub tree is leaf
			}
		}
		if(word.length()-1==offset){//the length of word equals the sub tree's level
			subTree.freqInc();//sub tree is a word end
		}else{//
			subTree.addNodes(word);//
		}
	}
	
	/**
	 * find word
	 * @param ccs
	 * @return
	 */
	public CharTree simpleMatch(CharSequence ccs){
		CharTree subTree = this.subTree(ccs.charAt(level+1));
		if(subTree!=null){
			if(ccs.length()-1==subTree.level){
				return subTree;
			}else{
				return subTree.simpleMatch(ccs);
			}
		}
		return null;
	}
	
	/**
	 * find word
	 * @param ccs
	 * @return
	 */
	public Boolean matchWithLenCheck(CharSequence ccs){
		CharTree subTree = this.subTree(ccs.charAt(level+1));
		if(subTree!=null){
			if(ccs.length()>subTree.level+subTree.maxSubNodesLength()+1)return Boolean.FALSE;
			if(ccs.length()-1==subTree.level){
				return subTree.isWord();
			}else{
				return subTree.matchWithLenCheck(ccs);
			}
		}
		return Boolean.FALSE;
	}
	
	/**
	 * positive max length match word
	 * @param ccs
	 * @return
	 */
	public int maxMatch(CharSequence ccs){
		return this.maxMatch(ccs, 0);
	}
	
	/**
	 * positive max length match word
	 * @param ccs
	 * @param flag
	 * @return
	 */
	public int maxMatch(CharSequence ccs, int flag){
		CharTree subTree = this.subTree(ccs.charAt(level+1));
		if(subTree!=null){
			if(subTree.isWord){
				flag = subTree.level;
			}
			if(ccs.length()-1>subTree.level&&!subTree.isLeaf){
				flag = subTree.maxMatch(ccs, flag);
			}
		}
		return flag;
	}
	
	/**
	 * reverse max length match word
	 * @param ccs
	 * @return
	 */
	public int revMaxMatch(CharSequence ccs){
		return this.revMaxMatch(ccs, 0);
	}
	
	/**
	 * reverse max length match word
	 * binding with the reverse dic
	 * @param flag 锟斤拷识偏锟狡筹拷锟饺ｏ拷锟斤拷锟叫的词筹拷为flag+1
	 */
	public int revMaxMatch(CharSequence ccs, int flag){
		int offset = ccs.length()-1-level;//锟斤拷前锟斤拷偏锟斤拷
		CharTree subTree = this.subTree(ccs.charAt(offset-1));//锟斤拷锟斤拷偏锟斤拷
		if(subTree!=null){//锟斤拷锟斤拷锟斤拷锟�
			if(subTree.isWord){//锟斤拷锟斤拷锟角达拷
				flag = subTree.level;//锟斤拷锟斤拷偏锟斤拷锟斤拷为锟斤拷锟斤拷牟慵�
			}
			if(ccs.length()-1>subTree.level&&!subTree.isLeaf){//锟斤拷锟斤拷锟斤拷址锟斤拷锟轿雌ワ拷锟斤拷锟街ｏ拷锟斤拷锟斤拷锟斤拷锟斤拷叶锟斤拷
				flag = subTree.revMaxMatch(ccs, flag);//锟斤拷锟斤拷锟斤拷锟斤拷匹锟斤拷
			}
		}
		return flag;
	}
	
	public CharTree subTree(Character key){
		return subTrees.get(key);
	}
	
	public Map<Character,CharTree> children(){
		return this.subTrees;
	}
	
	public Boolean isWord(){
		return this.isWord;
	}
	
	public int maxSubNodesLength(){
		return this.maxSubNodesLength;
	}
	
	public Integer freq(){
		return this.freq;
	}
	
	public Double mi(){
		return this.mi;
	}
	
	public Double conf(){
		return this.conf;
	}
	
	public void freqInc(){
		this.freq++;
	}
	
	public int level(){
		return this.level;
	}

	public Integer freqWhole() {
		// TODO Auto-generated method stub
		return null;
	}

}
